package br.ufrj.dcc.dm.util.preprocessors;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

import br.ufrj.dcc.dm.model.AttributeMetadata;

public class ArffPreProcessor extends PreProcessor {

	private static final String TO_IGNORE_LINE_CHAR = "@";
	private static final String OUTPUT_SUFFIX = "-output";
	private static final String EXTENSION_SUFFIX = ".arff";
	
	private static final String ATTRIBUTE_METADATA_PREFIX = "@attribute";
	private static final String OPEN_BRACKET_ATTRIBUTE_VALUES = "{";
	private static final String CLOSE_BRACKET_ATTRIBUTE_VALUES = "}";
	
	private static final String ATTRIBUTE_VALUE_SEPARATOR = ",";
	
	private String datasetPath;
	
	private LinkedHashMap<Integer, AttributeMetadata> attributeMetadataMap = new LinkedHashMap<Integer, AttributeMetadata>();
	private int attributeIndex = 0;
	
	public ArffPreProcessor(String datasetPath)
	{
		this.datasetPath = datasetPath;
	}

	@Override
	public String preProcess() 
	{
		String outputFilePath = createOutputFilePath();
		
		try 
		{
			FileReader fr = new FileReader(datasetPath);
			FileWriter fw = new FileWriter(outputFilePath);
			BufferedReader inputReader = new BufferedReader(fr);
			BufferedWriter outputWriter = new BufferedWriter(fw);
			String line;
			
			try
			{
				while( (line = inputReader.readLine())!= null )
				{
					if(isRelevant(line))
					{
						outputWriter.write(line + "\n");
					}
					else
					{
						if(isMetadata(line))
						{
							attributeMetadataMap.put(attributeIndex, (extractAttributeMetadata(line)));
							attributeIndex ++;
						}
					}
				}
			} 
			catch (IOException e) 
			{
				e.printStackTrace();
			}
			finally 
			{
				fw.flush();
				inputReader.close();
				outputWriter.close();
			}
			
		}
		catch (FileNotFoundException e) 
		{
			System.out.println("Couldn't open file "+ datasetPath);
			e.printStackTrace();
		}
		catch (IOException e)
		{
			System.out.println("Couldn't open file "+ datasetPath);
			e.printStackTrace();
		}
		
		return outputFilePath;
	}

	private AttributeMetadata extractAttributeMetadata(String line)
	{
		String trimmedLine = line.trim();
		trimmedLine = trimmedLine.replace(ATTRIBUTE_METADATA_PREFIX + " ","");
		
		int openBracketIndex = trimmedLine.indexOf(OPEN_BRACKET_ATTRIBUTE_VALUES);
		int closeBracketIndex = trimmedLine.lastIndexOf(CLOSE_BRACKET_ATTRIBUTE_VALUES);
		String attributeName = trimmedLine.substring(0, openBracketIndex).trim();
		
		String listOfPossibleValuesAsString = trimmedLine.substring(openBracketIndex + 1, closeBracketIndex).trim();
		String[] listOfPossibleValues = listOfPossibleValuesAsString.replace(" ", "").split(ATTRIBUTE_VALUE_SEPARATOR);
		
		return new AttributeMetadata(attributeName, listOfPossibleValues);
	}
	
	private boolean isMetadata(String line)
	{
		if(line.startsWith(ATTRIBUTE_METADATA_PREFIX))
		{
			return true;
		}
		
		return false;
	}
	
	private boolean isRelevant(String line)
	{
		if(isBlankLine(line) || isToIgnoreLine(line))
		{
			return false;
		}
		
		return true;
	}
	
	private boolean isBlankLine(String line)
	{
		if(line.trim().isEmpty())
		{
			return true;
		}
		
		return false;
	}
	
	private boolean isToIgnoreLine(String line)
	{
		if(line.trim().startsWith(TO_IGNORE_LINE_CHAR))
		{
			return true;
		}
		
		return false;
	}
	
	private String createOutputFilePath()
	{
		StringBuffer outputPath = new StringBuffer();
		
		String[] path = datasetPath.split("/");
		int lastIndexOfSlash = datasetPath.lastIndexOf("/");
		
		String filePath = datasetPath.substring(0, lastIndexOfSlash);
		String fileName = datasetPath.substring(lastIndexOfSlash);
		
		fileName = fileName.replace(EXTENSION_SUFFIX, OUTPUT_SUFFIX + EXTENSION_SUFFIX);
		
		outputPath.append(filePath);
		outputPath.append(fileName);
		
		return outputPath.toString();
	}

	public Map<Integer, AttributeMetadata> getAttributeMetadataMap()
	{
		return attributeMetadataMap;
	}
}
